import BN from "../../../bn.js";
import * as utils from "../utils";
'use strict';
var assert = utils.assert;
function KeyPair(ec, options) {
    this.ec = ec;
    this.priv = null;
    this.pub = null;
    // KeyPair(ec, { priv: ..., pub: ... })
    if (options.priv)
        this._importPrivate(options.priv, options.privEnc);
    if (options.pub)
        this._importPublic(options.pub, options.pubEnc);
}
KeyPair.fromPublic = function fromPublic(ec, pub, enc) {
    if (pub instanceof KeyPair)
        return pub;
    return new KeyPair(ec, {
        pub: pub,
        pubEnc: enc,
    });
};
KeyPair.fromPrivate = function fromPrivate(ec, priv, enc) {
    if (priv instanceof KeyPair)
        return priv;
    return new KeyPair(ec, {
        priv: priv,
        privEnc: enc,
    });
};
KeyPair.prototype.validate = function validate() {
    var pub = this.getPublic();
    if (pub.isInfinity())
        return { result: false, reason: 'Invalid public key' };
    if (!pub.validate())
        return { result: false, reason: 'Public key is not a point' };
    if (!pub.mul(this.ec.curve.n).isInfinity())
        return { result: false, reason: 'Public key * N != O' };
    return { result: true, reason: null };
};
KeyPair.prototype.getPublic = function getPublic(compact, enc) {
    // compact is optional argument
    if (typeof compact === 'string') {
        enc = compact;
        compact = null;
    }
    if (!this.pub)
        this.pub = this.ec.g.mul(this.priv);
    if (!enc)
        return this.pub;
    return this.pub.encode(enc, compact);
};
KeyPair.prototype.getPrivate = function getPrivate(enc) {
    if (enc === 'hex')
        return this.priv.toString(16, 2);
    else
        return this.priv;
};
KeyPair.prototype._importPrivate = function _importPrivate(key, enc) {
    this.priv = new BN(key, enc || 16);
    // Ensure that the priv won't be bigger than n, otherwise we may fail
    // in fixed multiplication method
    this.priv = this.priv.umod(this.ec.curve.n);
};
KeyPair.prototype._importPublic = function _importPublic(key, enc) {
    if (key.x || key.y) {
        // Montgomery points only have an `x` coordinate.
        // Weierstrass/Edwards points on the other hand have both `x` and
        // `y` coordinates.
        if (this.ec.curve.type === 'mont') {
            assert(key.x, 'Need x coordinate');
        }
        else if (this.ec.curve.type === 'short' ||
            this.ec.curve.type === 'edwards') {
            assert(key.x && key.y, 'Need both x and y coordinate');
        }
        this.pub = this.ec.curve.point(key.x, key.y);
        return;
    }
    this.pub = this.ec.curve.decodePoint(key, enc);
};
// ECDH
KeyPair.prototype.derive = function derive(pub) {
    if (!pub.validate()) {
        assert(pub.validate(), 'public point not validated');
    }
    return pub.mul(this.priv).getX();
};
// ECDSA
KeyPair.prototype.sign = function sign(msg, enc, options) {
    return this.ec.sign(msg, this, enc, options);
};
KeyPair.prototype.verify = function verify(msg, signature) {
    return this.ec.verify(msg, signature, this);
};
KeyPair.prototype.inspect = function inspect() {
    return '<Key priv: ' + (this.priv && this.priv.toString(16, 2)) +
        ' pub: ' + (this.pub && this.pub.inspect()) + ' >';
};
export default KeyPair;
